package com.jifen.pay.service;

import com.alibaba.fastjson.JSONObject;
import com.jifen.common.MyException;
import com.jifen.config.Global;
import com.jifen.constant.ErrorCode;
import com.jifen.mch.dao.MchPayDao;
import com.jifen.mch.entity.MchPay;
import com.jifen.mch.service.MchService;
import com.jifen.mch.vo.QrCodeVo;
import com.jifen.user.dao.UserDao;
import com.jifen.user.dao.UserPayDao;
import com.jifen.user.entity.User;
import com.jifen.user.entity.UserPay;
import com.jifen.user.service.UserService;
import com.jifen.user.vo.TokenUserVo;
import com.jifen.utils.DateUtils;
import com.jifen.utils.SystemUtils;
import com.jifen.utils.WxPaySignatureUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 类名：Wexin
 * 作者：zhangtao
 * 日期：2019/7/2 11:11
 * 版本：1.0.0
 * 描述：TODO
 **/
@Service
public class WeixinService {
    private Logger LOG = LoggerFactory.getLogger(WeixinService.class);
    private final String APPID = "wx24401f58a9da2c41";
    private final String MCHID = "1542140181";
    private final String KEY = "5ed746dfd69e48a498d3e70ccae8f7e9";

    @Autowired
    RestTemplate restTemplate;
    @Resource
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    MchService mchService;
    @Autowired
    MchPayDao mchPayDao;
    @Autowired
    UserPayDao userPayDao;
    @Autowired
    UserService userService;
    @Autowired
    UserDao userDao;

    private static AtomicInteger counter = new AtomicInteger(1);

    public static int getCount() {
        return counter.getAndIncrement();
    }


    /**
     * 商家充值积分
     * @param token
     * @param jifen
     * @param ip
     * @return
     */
    public Object mchRecharge(String token, int jifen, String ip) {
        TokenUserVo tokenUser = userService.getTokenUser(token);
        String tradeNo = DateUtils.formatDate("yyyyMMddHHmmssms") + getCount();
        System.out.println("微信商户充值");
        String nonceStr = UUID.randomUUID().toString().replace("-", "");
        // 商户订单号
        SortedMap<String, Object> parame = new TreeMap<>();
        parame.put("appid", APPID);
        parame.put("mch_id", MCHID);
        parame.put("nonce_str", nonceStr);
        parame.put("body", "购买积分");
        parame.put("out_trade_no", tradeNo);
        parame.put("total_fee", "1");
        parame.put("spbill_create_ip", ip);
        parame.put("notify_url", Global.getConfig("payDomain")+"/jf/1/pay/mch/recharge/weixin/callback");
        parame.put("trade_type", "APP");
        String sign = WxPaySignatureUtils.signature(parame, KEY);
        parame.put("sign", sign);
        String xml = getRequestXML(parame);
        ResponseEntity<String> respString = restTemplate.postForEntity("https://api.mch.weixin.qq.com/pay/unifiedorder", xml, String.class);
        Map<String, Object> rstMap = new HashMap<>();
        if (respString.getStatusCodeValue() == 200) {
            rstMap.put("partnerId", MCHID);
            rstMap.put("timeStamp", System.currentTimeMillis()/1000L);
            rstMap.put("packageValue", "Sign=WXPay");
            String xmlBody = respString.getBody();
            LOG.info("微信支付-响应：{}", xmlBody);
            try {
                Document doc = DocumentHelper.parseText(xmlBody);
                Element rootElt = doc.getRootElement();
                Iterator iter = rootElt.elementIterator();
                while (iter.hasNext()) {
                    Element recordEle = (Element) iter.next();
                    String name = recordEle.getName();
                    String value = recordEle.getText();
                    if (name.equals("return_code")) {
                        if (!value.equals("SUCCESS")) {
                            System.out.println("支付失败");
                        }
                    }
                    if (name.equals("nonce_str")) {
                        rstMap.put("nonceStr", value);
                    } else if (name.equals("prepay_id")) {
                        rstMap.put("prepayId", value);
                    } else if (name.equals("sign")) {
                        rstMap.put("sign", value);
                    }
                }
            } catch (DocumentException e) {
                System.out.println("支付失败");
                e.printStackTrace();
            }
            // 插入支付记录
            MchPay mchPay = new MchPay();
            mchPay.setPayType(1);
            mchPay.setJifen(jifen);
            mchPay.setTradeNo(tradeNo);
            mchPay.setUid(tokenUser.getMchId());
            mchPay.setCreateTime(DateUtils.getDate());
            mchPayDao.insertSelective(mchPay);

            SortedMap<String, Object> params = new TreeMap<>();
            params.put("appid", APPID);
            params.put("partnerid", MCHID);
            params.put("prepayid",  rstMap.get("prepayId"));
            params.put("package",  rstMap.get("packageValue"));
            params.put("noncestr", rstMap.get("nonceStr"));
            params.put("timestamp", rstMap.get("timeStamp"));
            sign = WxPaySignatureUtils.signature(params, KEY);
            rstMap.put("sign", sign);
        }
        return rstMap;
    }

    /**
     * 商家充值积分回调
     * @param request
     * @return
     * @throws Exception
     */
    public String mchRechargeCallback(HttpServletRequest request) throws Exception {
        String rstXml = null;
        BufferedReader reader = null;
        reader = request.getReader();
        String line = "";
        String xmlString = null;
        StringBuffer inputString = new StringBuffer();
        while ((line = reader.readLine()) != null) {
            inputString.append(line);
        }
        xmlString = inputString.toString();
        request.getReader().close();
        LOG.info("[微信支付回调]：{}", xmlString);
        SortedMap<String, Object> smap = new TreeMap<>();
        Document doc = DocumentHelper.parseText(xmlString);
        Element root = doc.getRootElement();
        for (Iterator iterator = root.elementIterator(); iterator.hasNext(); ) {
            Element e = (Element) iterator.next();
            smap.put(e.getName(), e.getText());
        }
        if (smap.get("return_code").toString().equals("SUCCESS")) {
            if (smap.get("result_code").toString().equals("SUCCESS")) {
                boolean bool = WxPaySignatureUtils.validateSign(smap, KEY);
                if (bool) {
                    String tradeNo = smap.get("out_trade_no").toString();
                    String outTradeNo = smap.get("transaction_id").toString();
                    // 业务
                    mchService.mchRecharge(tradeNo, outTradeNo);
                    StringBuffer sbf = new StringBuffer();
                    sbf.append("<xml>");
                    sbf.append("<return_code><![CDATA[SUCCESS]]></return_code>");
                    sbf.append("<return_msg><![CDATA[OK]]></return_msg>");
                    sbf.append("</xml>");
                    rstXml = sbf.toString();
                }
            }
        }
        return rstXml;
    }

    /**
     * 超市现金消费
     * @param token
     * @param content
     * @param ip
     * @return
     */
    public Object smarketTrade(String token, String content, String ip) {
        TokenUserVo tokenUser = userService.getTokenUser(token);
        Map<String, Object> rstMap = new HashMap<>();
        QrCodeVo qrCodeVo = (QrCodeVo)redisTemplate.opsForValue().get(content);
        if(qrCodeVo!=null) {
            User account = userDao.getAccount(tokenUser.getId());
            BigDecimal deductBalance = new BigDecimal(account.getDeductMoney());
            BigDecimal deductMoney = new BigDecimal(qrCodeVo.getDeductMoney());
            if (deductBalance.compareTo(deductMoney)==-1) {
                throw new MyException(ErrorCode.DEDUCT_MONEY_BUZU);
            }
            String tradeNo = DateUtils.formatDate("yyyyMMddHHmmssms") + getCount();
            String nonceStr = UUID.randomUUID().toString().replace("-", "");
            // 商户订单号
            SortedMap<String, Object> parame = new TreeMap<>();
            parame.put("appid", APPID);
            parame.put("mch_id", MCHID);
            parame.put("nonce_str", nonceStr);
            parame.put("body", "超市消费");
            parame.put("out_trade_no", tradeNo);
            parame.put("total_fee", "1");//qrCodeVo.getPayMoney()*100;
            parame.put("spbill_create_ip", ip);
            parame.put("notify_url", Global.getConfig("payDomain") + "/jf/1/pay/smarket/trade/weixin/callback");
            parame.put("trade_type", "APP");
            JSONObject attach = new JSONObject();
            attach.put("mobile", tokenUser.getMobile());
            attach.put("deductMoney", qrCodeVo.getDeductMoney());
            attach.put("qrcodeContent", content);
            parame.put("attach", attach.toString());

            String sign = WxPaySignatureUtils.signature(parame, KEY);
            parame.put("sign", sign);
            String xml = getRequestXML(parame);
            ResponseEntity<String> respString = restTemplate.postForEntity("https://api.mch.weixin.qq.com/pay/unifiedorder", xml, String.class);
            if (respString.getStatusCodeValue() == 200) {
                rstMap.put("partnerId", MCHID);
                rstMap.put("timeStamp", System.currentTimeMillis() / 1000L);
                rstMap.put("packageValue", "Sign=WXPay");
                String xmlBody = respString.getBody();
                LOG.info("微信支付-响应：{}", xmlBody);
                try {
                    Document doc = DocumentHelper.parseText(xmlBody);
                    Element rootElt = doc.getRootElement();
                    Iterator iter = rootElt.elementIterator();
                    while (iter.hasNext()) {
                        Element recordEle = (Element) iter.next();
                        String name = recordEle.getName();
                        String value = recordEle.getText();
                        if (name.equals("return_code")) {
                            if (!value.equals("SUCCESS")) {
                                System.out.println("支付失败");
                            }
                        }
                        if (name.equals("nonce_str")) {
                            rstMap.put("nonceStr", value);
                        } else if (name.equals("prepay_id")) {
                            rstMap.put("prepayId", value);
                        } else if (name.equals("sign")) {
                            rstMap.put("sign", value);
                        }
                    }
                } catch (DocumentException e) {
                    System.out.println("支付失败");
                    e.printStackTrace();
                }
                // 插入支付记录
                UserPay userPay = new UserPay();
                userPay.setPayType(1);
                userPay.setAmount(new BigDecimal(qrCodeVo.getPayMoney()));
                userPay.setTradeNo(tradeNo);
                userPay.setUid(tokenUser.getId());
                userPay.setCreateTime(DateUtils.getDate());
                userPayDao.insertSelective(userPay);

                SortedMap<String, Object> params = new TreeMap<>();
                params.put("appid", APPID);
                params.put("partnerid", MCHID);
                params.put("prepayid", rstMap.get("prepayId"));
                params.put("package", rstMap.get("packageValue"));
                params.put("noncestr", rstMap.get("nonceStr"));
                params.put("timestamp", rstMap.get("timeStamp"));
                sign = WxPaySignatureUtils.signature(params, KEY);
                rstMap.put("sign", sign);
            }
        }else{
            throw new MyException(ErrorCode.QRCODE_INVALID);
        }
        return rstMap;
    }

    /**
     * 超市现金消费回调
     * @param request
     * @return
     * @throws Exception
     */
    public String smarketTradeCallback(HttpServletRequest request) throws Exception {
        String rstXml = null;
        BufferedReader reader = null;
        reader = request.getReader();
        String line = "";
        String xmlString = null;
        StringBuffer inputString = new StringBuffer();
        while ((line = reader.readLine()) != null) {
            inputString.append(line);
        }
        xmlString = inputString.toString();
        request.getReader().close();
        LOG.info("[微信支付回调]：{}", xmlString);
        SortedMap<String, Object> smap = new TreeMap<>();
        Document doc = DocumentHelper.parseText(xmlString);
        Element root = doc.getRootElement();
        for (Iterator iterator = root.elementIterator(); iterator.hasNext(); ) {
            Element e = (Element) iterator.next();
            smap.put(e.getName(), e.getText());
        }
        if (smap.get("return_code").toString().equals("SUCCESS")) {
            if (smap.get("result_code").toString().equals("SUCCESS")) {
                boolean bool = WxPaySignatureUtils.validateSign(smap, KEY);
                if (bool) {
                    String tradeNo = smap.get("out_trade_no").toString();
                    String outTradeNo = smap.get("transaction_id").toString();
                    JSONObject attach = JSONObject.parseObject(smap.get("attach").toString());
                    // 业务
                    userService.smarketTrade(tradeNo, outTradeNo, attach.getString("qrcodeContent"), attach.getDouble("deductMoney"), attach.getString("mobile"));
                    StringBuffer sbf = new StringBuffer();
                    sbf.append("<xml>");
                    sbf.append("<return_code><![CDATA[SUCCESS]]></return_code>");
                    sbf.append("<return_msg><![CDATA[OK]]></return_msg>");
                    sbf.append("</xml>");
                    rstXml = sbf.toString();
                }
            }
        }
        return rstXml;
    }


    //拼接xml 请求路径
    public static String getRequestXML(SortedMap<String, Object> parame) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("<xml>");
        Set set = parame.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            //过滤相关字段sign
            if ("sign".equalsIgnoreCase(key)) {
                buffer.append("<" + key + ">" + "<![CDATA[" + value + "]]>" + "</" + key + ">");
            } else {
                buffer.append("<" + key + ">" + value + "</" + key + ">");
            }
        }
        buffer.append("</xml>");
        return buffer.toString();
    }
}
